library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity exponentiation_Fsm is
	
	generic ( Z : positive range 1 to 256 ) ;
	
	port (
		clk : in std_logic ;
		start : in std_logic ;
		reset : in std_logic ;
		bit_utile : in std_logic_vector (Z-1 downto 0);  --Nombre de bit à prendre en
							--compte de notre puissance
		p : in std_logic_vector(Z-1 downto 0);  --Puissance à la quelle nous
							--voulons exponentier
		a : in  std_logic_vector(Z-1 downto 0);  --Variable à exponentier
		cmdMult : out std_logic_vector(1 downto 0);  -- 0=X1 / 1=X2 Pour la multiplication
		cmdX : out std_logic;               --Choix du registre de sauvegarde
							--(0=X1 1 = X2)

                is_ok : out std_logic;
		cmdSave :  out std_logic            
	);
	
end entity;

--------------------------------------------------------


architecture fsm_1 of exponentiation_Fsm is
	
	signal B : std_logic_vector(Z-1 downto 0);
	signal i : signed (Z-1 downto 0) ;
	
	type state is ( S0, S1,S_att, S2, S3, S4, S5, S6, S7, S8);
	
	signal etat_courant : state;
	signal etat_suivant : state;
	
begin

	P_etat: process (clk, reset)
	begin  -- process P_etat
		if reset = '1' then             -- asynchronous reset (active low)
		etat_courant <= S0;
		i <= signed(bit_utile) ;
                B <= (others => '0');
				
		elsif clk'event and clk = '1' then  -- rising clock edge
		etat_courant <= etat_suivant;
			if( etat_suivant = S3) then       --On décrémente i que lorsque nous passons dans S3
				i <= i-1;
                        elsif (etat_suivant = S1) then
                          	B <= p;
			end if; 
		end if;
	end process P_etat;
	
	
	suivant: process (etat_courant,start)
	begin  -- process suivant

		etat_suivant <= S0;
	
		cmdMult <= "00";
		cmdX <= '0';
		cmdSave <='0';
		is_ok <= '0';
		case etat_courant is
		
		when S0 => if start = '1' then
				etat_suivant <= S1;
			else
				etat_suivant <= S0;
			end if;
			
		when S1 =>
                  is_ok <= '1';
                  etat_suivant <= S2;
                when S_att =>
                  etat_suivant <= S2;
		when S2 =>
			cmdMult <= "00";             --Multiplication de X1 par X1
			cmdX <= '1';                 -- Stockage dans X2
			cmdSave <= '1';
			etat_suivant <= S3 ;

			
		when S3 =>
			cmdSave <= '0';
			if i < 0 then
				etat_suivant <= S8;
			else
				if B(to_integer(i)) = '0' then
					etat_suivant <= S4;
				else
					etat_suivant <= S6;
				end if;
			end if;
			

		when S4 =>
			cmdMult <= "01";
			cmdX <= '1';
			cmdSave <= '1';
			etat_suivant <= S5;
			
		when S5 =>
			cmdMult <= "00";
			cmdX <= '0';
			cmdSave <= '1';
			etat_suivant <= S3;
			
			
		when S6 =>
			cmdMult <= "01";
			cmdX <= '0';
			cmdSave <= '1';
			etat_suivant <= S7;
			
		when S7 =>
			cmdMult <= "11";
			cmdX <= '1';
			cmdSave <= '1';
			etat_suivant <= S3;
			
		when S8 =>
		
			etat_suivant <= S8;
			
		when others => null;
		
		end case;
		
	end process suivant;

end fsm_1;

